package Main;

/*
 *
 * Copyright (c) 2007, Sun Microsystems, Inc.
 *
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *  * Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *  * Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *  * Neither the name of Sun Microsystems nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

import java.io.*;
import java.util.Enumeration;
import java.util.Vector;
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
import javax.microedition.media.*;
import javax.microedition.media.control.VideoControl;
import javax.microedition.io.file.*;
import javax.microedition.io.*;


public class LAPSEBasic extends MIDlet implements CommandListener, ItemStateListener
{
    private Player player;
    private VideoControl vidCtrl = null;

    private final Command exitCommand = new Command("Exit", Command.EXIT, 2);
    private final Command backCommand = new Command("Back", Command.BACK, 1);  
    private final Command startShootingCommand = new Command("Start", Command.SCREEN, 1);
    private final Command stopShootingCommand = new Command("Stop", Command.SCREEN, 1);
    private final Command setTimerCommand = new Command("Set delay", Command.SCREEN, 2);
    private final Command setStorageCommand = new Command("Set storage", Command.SCREEN, 3);
    private final Command showTraceCommand = new Command("Show log", Command.SCREEN, 4);
    
    private Display display;
    private Form vidForm;
    private Item videoItem;
    
    private String PHOTOS_DIR = null;
    
    private boolean shooting = false;
    private int time = 10000;
    
    private Form timerForm;
    private ChoiceGroup times;
    
    private Form locationForm;
    private ChoiceGroup storageLocs;
    private Vector locs = new Vector();
    
    private Form traceForm;    


    public LAPSEBasic() 
    {
        // Set up timer form
        timerForm = new Form("Select time delay:");
        String timesInt[] = {"1/2sec", "1sec", "2sec", "5sec", "10sec", "20sec", "30sec", "1min", "2min", "5min", "10min"};
        times = new ChoiceGroup(null, Choice.EXCLUSIVE, timesInt, null);
        times.setSelectedIndex(4, true);//When default is 10sec
        timerForm.append(times);
        timerForm.setItemStateListener(this);
        timerForm.setCommandListener(this);
        timerForm.addCommand(backCommand);   
        
        //Set up trace form
        traceForm = new Form("LAPSE Log");  
        traceForm.addCommand(backCommand);   
        traceForm.setCommandListener(this);
        
        //Set up video form
        vidForm = new Form("LAPSE Basic");
        display = Display.getDisplay(this);
        display.setCurrent(vidForm);
        vidForm.addCommand(setStorageCommand);
        vidForm.addCommand(setTimerCommand);
        vidForm.addCommand(startShootingCommand);
        vidForm.addCommand(showTraceCommand);
        vidForm.addCommand(exitCommand);    
        vidForm.setCommandListener(this);
        
        // Create LAPSE default folder
        Enumeration roots = FileSystemRegistry.listRoots();
        String root = "";
        
        while(roots.hasMoreElements())
        {
            root = (String)roots.nextElement();
            locs.addElement(root);
            trace("Found storage root: " + root);
        }
        trace("Using: " + root);
        createDirByRoot(root);
        
        String locsArr[] = new String[locs.size()];
        locs.copyInto(locsArr);

        // Set up location form
        locationForm = new Form("Select storage location:");
        storageLocs = new ChoiceGroup(null, Choice.EXCLUSIVE, locsArr, null);
        locationForm.append(storageLocs);
        locationForm.setItemStateListener(this);
        locationForm.setCommandListener(this);
        locationForm.addCommand(backCommand);   
        
        // Initialise video control
        try 
        {           
            player = Manager.createPlayer("capture://video");
            player.prefetch();
            player.realize();
            
            vidCtrl = (VideoControl)player.getControl("VideoControl");
            if (vidCtrl != null) 
            {
                videoItem = (Item)vidCtrl.initDisplayMode(VideoControl.USE_GUI_PRIMITIVE, null);
                vidCtrl.setDisplaySize(vidForm.getWidth(), vidForm.getHeight());
                vidForm.append(videoItem);
            } 
            else 
            {
                trace("Cannot use the camera on this device!");
                return;
            }
        }
        catch(MediaException me) 
        {
            traceErr(me);
        }
        catch(IOException ioe) 
        {
            traceErr(ioe);
        }
    }
    
    private void trace(String trace)
    {
        System.out.println(trace);
        traceForm.append(trace + "\n");
    }
    
    private void traceErr(Exception err)
    {
        err.printStackTrace();
        trace("Error:" + err.getMessage());
    }    
    
    private void createDirByRoot(String root) 
    {
        String folders[] = {"", "Pictures/", "Images/"}; 
        boolean success = false;

        for(int i = 0; i < folders.length; i++)    
        {
            if(success)
                break;

            try 
            {
                PHOTOS_DIR = "file:///" + root + folders[i] + "LAPSE";
                createDirByName(PHOTOS_DIR);
                success = true;
            }
            catch(IOException ioe) 
            {
                trace("Failed to create folder:\n" + PHOTOS_DIR);
                traceErr(ioe);   
            }                
        }
    }
    
    private void createDirByName(String dir) throws IOException
    {
            FileConnection fconn = (FileConnection)Connector.open(dir);
            if (!fconn.exists())
            {
                trace("Creating folder:");
                trace(dir);
                fconn.mkdir();
                trace("Setting folder writeable");
                fconn.setWritable(true);
                trace("Setting folder readable");
                fconn.setReadable(true);
                trace("Folder created");
            }
            else
                trace("Folder already exists");
    }

    public void startApp() 
    {
        try 
        {
            player.start();
        } 
        catch(MediaException me) 
        {
            traceErr(me);
        }
    }

    public void pauseApp() 
    {
        if (vidCtrl != null) 
        {
            startStopShooting();
        }
        try 
        {
            player.stop();
        } 
        catch (MediaException me) 
        {
            traceErr(me);
        }
    }

    public void destroyApp(boolean unconditional) 
    {
        closePlayer();
        notifyDestroyed();
    }

    /*
     * Respond to commands, including back
     */
    public void commandAction(Command c, Displayable s) 
    {
        if (c == backCommand) 
        {
            display.setCurrent(vidForm);
        } 
        if (s == vidForm) 
        {
            if (c == exitCommand) 
            {
                destroyApp(false);
            } 
            else if (c == startShootingCommand) 
            {
                startStopShooting();
            } 
            else if (c == stopShootingCommand) 
            {
                startStopShooting();
            } 
            else if (c == setStorageCommand) 
            {
                display.setCurrent(locationForm);
            } 
            else if (c == setTimerCommand) 
            {
                display.setCurrent(timerForm);
            }
            else if (c == showTraceCommand) 
            {
                display.setCurrent(traceForm);
            }
        } 
    }
      
    public void itemStateChanged(Item item) 
    {
        try 
        {
            if (item != null) 
            {
                if (item == times)
                {
                    //String t[] = {"1/2sec", "1sec", "2sec", "5sec", "10sec", "20sec", "30sec", "1min", "2min", "5min", 10min};
                    int tIndex = times.getSelectedIndex();
                    switch (tIndex) 
                    {
                        case 0: time = 500; break;
                        case 1: time = 1000; break;
                        case 2: time = 2000; break;
                        case 3: time = 5000; break;
                        case 4: time = 10000; break;
                        case 5: time = 20000; break;
                        case 6: time = 30000; break;
                        case 7: time = 60000; break;
                        case 8: time = 120000; break;
                        case 9: time = 300000; break;
                        case 10: time = 600000; break;
                    }   
                    trace("Delay set to " + Integer.toString(time) + "ms");
                    display.setCurrent(vidForm);
                }
                else if(item == storageLocs)
                {
                    String loc = storageLocs.getString(storageLocs.getSelectedIndex());
                    trace("Changing storage to " + loc);
                    createDirByRoot(loc);
                    display.setCurrent(vidForm);
                }
            }
        } 
        catch (Exception e) 
        {
            traceErr(e);
        }
    }
    
    private void startStopShooting() 
    {
        if(shooting)
        {
            trace("Stopping shooting");
            shooting = false;    
            vidForm.removeCommand(stopShootingCommand);
            vidForm.addCommand(startShootingCommand);
            return;
        }
        else
        {
            trace("Starting shooting");
            shooting = true;
            vidForm.removeCommand(startShootingCommand);
            vidForm.addCommand(stopShootingCommand);
        }
        
        new Thread() 
        {
            public void run() 
            {                              
                try 
                {                    
                    long stime = System.currentTimeMillis();
                    createDirByName(PHOTOS_DIR + "/" + stime);
                    
                    while(shooting)
                    {
                        byte [] snap = vidCtrl.getSnapshot("encoding=jpeg");
                        if (snap != null) 
                        {
                            FileConnection fileConnection = (FileConnection)Connector.open(PHOTOS_DIR + "/" + stime + "/" + System.currentTimeMillis() + ".jpg", Connector.READ_WRITE);
                            if (!fileConnection.exists())
                                fileConnection.create();
                            OutputStream outputStream = fileConnection.openOutputStream();
                            outputStream.write(snap);
                            outputStream.close();
                            fileConnection.close();      
                            trace("Shot " + System.currentTimeMillis() + " taken");
                        }
                        Thread.sleep(time);
                     }
                } 
                catch (MediaException me) 
                {
                    traceErr(me);
                }
                catch (InterruptedException ie) 
                {
                    traceErr(ie);
                }
                catch (IOException io) 
                {
                    traceErr(io);
                }
            }
        }.start();
    }

    private void closePlayer() 
    {
        if (player != null) 
        {
            player.close();
            player = null;
        }
    }
}